#include "dht11.h"

/*
PG9 ---DHT11
*/
void Dht11_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

	//GPIO初始化 
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//引脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT ;//输出模式
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;//浮空
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;//速度
	GPIO_Init(GPIOG, &GPIO_InitStruct);
	
	//空闲状态是高电平
	PGout(9) = 1;
}

//引脚模式的变更
void Dht11_Pin_Mode(GPIOMode_TypeDef mode)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//GPIO初始化 
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//引脚
	GPIO_InitStruct.GPIO_Mode = mode ;//模式
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;//浮空
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;//速度
	GPIO_Init(GPIOG, &GPIO_InitStruct);
}

int Dht11_Start(void)
{
	u16 t=0;
	
	//1.把电平的模式设置为输出模式
	Dht11_Pin_Mode(GPIO_Mode_OUT);
	
	//最开始空闲状态是高电平
	PGout(9) = 1;
	delay_ms(2);
	//主机至少拉低18ms 
	PGout(9) = 0;
	delay_ms(20);
	//主机拉高20-40us
	PGout(9) = 1;
	delay_us(30);
	
	//响应信号
	//引脚切换为输入模式
	Dht11_Pin_Mode(GPIO_Mode_IN);
	
	//检测响应信号的低电平的开始
	while(1)
	{
		if(PGin(9) == 0)
			break;
		t++;
		delay_us(2);
		
		if(t>=20) //40us
			return -1;
	}
	//此时这里就是响应信号低电平开始的地方
	delay_us(50);
	
	//把响应信号低电平的时间消耗掉
	t=0;
	while(1)
	{
		if(PGin(9) == 1)
			break;
	
		delay_us(2);
		t++;
		if(t>=50) //100us 如果这么长时间还不退出，那可能是异常了 直接退出
			return -2;
	}
	
	//到了 DHT拉高80us 最开始高电平的地方
	delay_us(50);
	//写一个循环，把高电平的持续时间消耗掉
	t=0;
	while(1)
	{
		if(PGin(9) == 0)
			break;
		
		delay_us(2);
		t++;
		if(t>=50) //100us 如果这么长时间还不退出，那可能是异常了 直接退出
			return -3;
	}
	
	//到了 开始传送数据 最开始的地方  低电平的起始点
	return 0;
}

//读取一个字节数据  而且是高位先出
uint8_t Dht11_Read_Byte(void)
{
	u8 i,t,data=0x00; //存储读取到的数据
	
	//一个字节有8个bit位 ，先bit7   bit6  bit5  bit4  bit3  bit2 bit1 bit0
	for(i=0; i<8; i++)
	{
		//每一个bit数据都是以50us的低电平开始
		//把低电平的时间消耗掉
		t=0;
		while(1)
		{
			if(PGin(9) == 1)
				break;
			delay_us(2);
			t++;
			if(t>=40)
				return 0;
		}
		//高电平的起始点
		//数字0的表示  高电平 26us~28us  数字1的表示 高电平 70us
		//延时40us，如果40us之后还是引脚还是高电平，那么说明此时数据为1
		delay_us(40);
		if(PGin(9) == 1)
		{
			//从高位开始
			data |= (0x01<<(7-i));
			
			//还要把剩下的高电平 消耗掉
			t=0;
			while(1)
			{
				if(PGin(9) == 0)
					break;
				delay_us(2);
				t++;
				if(t>=40)
					return 0;	
			}
		}
	}
	
	return data;
}

int Dht11_Data(u8 *data)
{
	//u8 data[5]; //data[0] 8bit的湿度整数  data[1] 8bit的湿度小数 data[2] 8bit的温度整数 data[3] 8bit的温度小数 data[4]校验和
	u8 i;
	
	for(i=0; i<5; i++)
	{
		data[i] = Dht11_Read_Byte();
	}
	
	if(data[4] == data[0] + data[1] + data[2] + data[3])
	{
		return 0;
	}
	
	return -1;
}
